var name = "汤姆.布鲁斯"; // 全局姓名
var age = 30; // 全局年龄

/* ---------------- 变量 ---------------- */
function test1001() {

}

function test1002() {

}

function test1003() {

}

function test1004() {

}

function test1005() {

}

function test1006() {

}

function test1007() {
	var g1 = ["Tom", "Jack"];
	var g2 = ["Lucy", "Anny"];
	var all = [...g1, ...g2];
	console.log("扩展运算符合并数组: ", all);

	var g3 = [...all];
	g3[0] = "汤姆";
	console.log("克隆数组:", all, g3);

	var h1 = document.getElementsByTagName("h3");
	var h2 = [...h1];
	console.log("将伪数组转为真数组:");
	console.log(h1);
	console.log(h2);
}

function test1008() {

}

function test1009() {
	var user = null;
	console.log("user=null: ", user?.school?.address?.city);

	user = {}
	console.log("user.school=null: ", user?.school?.address?.city);

	user = {
		school: {
			name: "New Star",
		}
	}
	console.log("user.school.address=null:", user?.school?.address?.city);

	user = {
		school: {
			name: "New Star",
			address: {}
		}
	}
	console.log("user.school.address.city=null:", user?.school?.address?.city);

	user = {
		school: {
			name: "New Star",
			address: {
				city: "Comos"
			}
		}
	}
	console.log("user.school.address.city= ", user?.school?.address?.city);
}

/* ---------------- 解构赋值 ---------------- */
function test1101() {

}

function test1102() {

}

function test1103() {

}

/* ---------------- 数据类型 ---------------- */
function test1201() {

}

function test1202() {

}

function test1203() {

}

function test1204() {

}

function test1205() {

}

function test1206() {
	var s1 = Symbol();
	var s2 = Symbol();

	console.log("Symbol 值与类型: ", s1, typeof(s1));
	console.dir(s1);
	console.log("无参调用Symbol，没有唯一性: ", s1 == s2);

	var s3 = Symbol("name");
	var s4 = Symbol("name");
	console.log("有参调用，参数只是描述，没有唯一性: ", s3 == s4);

	var s5 = Symbol.for("red");
	var s6 = Symbol.for("red");
	console.log("Symbol.for 注册到全局，有唯一性: ", s5 == s6);

	var s5key = Symbol.keyFor(s5);
	console.log("Symbol.keyFor 返回Symbol实例的key: ", s5, s5key);

	// 作为枚举
	var Colors = {
		Red: Symbol(),
		Blue: Symbol(),
		Green: Symbol()
	}
	var s7 = Colors.Red;
	console.log("场景一，用作枚举: ", s7 == Colors.Red, s7 == Colors.Blue);

	// 作为对象属性
	var s8 = Symbol("name");
	var user = {
		[s8]: "Tom",
		age: 20
	}
	console.log("场景二，作为对象属性: ", user[s8]);

}
/* ---------------- 流程控制 ---------------- */
function test1301() {
	var age = 15;
	if (age < 5) {
		console.log("儿童");
	} else if (age < 18) {
		console.log("少年");
	} else if (age < 40) {
		console.log("青年");
	} else if (age < 65) {
		console.log("壮年");
	} else {
		console.log("老年");
	}
}

function test1302() {

}

function test1303() {
	var i = 0,
		sum = 0;
	while (i < 10) {
		sum += i++;
	}
	console.log(sum);
}

function test1304() {

}

function test1305() {
	var foods = ["苹果", "香蕉", "桔子"];
	// for of 遍历数组, 遍历项为数组元素
	for (var item of foods) {
		console.log(item);
	}
}

function test1306() {
	var user = {
		name: "Tom",
		age: 20,
		gender: "male"
	};

	// for in 遍历对象，遍历项为键
	for (key in user) {
		console.log(key + " = " + user[key]);
	}
}

function test1307() {
	var foods = ["苹果", "香蕉", "桔子"];
	foods.forEach((value, index, array) => {
		console.log(`[${index}] = ${value}`);
	});
}

function test1308() {

}
/* ---------------- 函数 ---------------- */
function test1401() {
	function f1() {
		console.log(`普通函数, name = ${name}`);
	}
	f1();

	function f2() {
		var name = "Jack";
		console.log(`局部变量覆盖全局, name = ${name}, window.name=${window.name}`);
	}
	f2();
}

function test1402() {
	function f1() {
		function f2() {
			console.log("嵌套函数内");
		}
		return f2;
	}
	var fn = f1();
	fn();
	// f1()();
}

function test1403() {
	function f1() {
		console.log("普通函数调用");
	}
	f1();

	var f2 = function() {
		console.log("表达式函数调用");
	};
	f2();

	var f3 = () => {
		console.log("箭头函数调用");
	};
	f3();

	var jack = {
		name: "Jack",
		show() {
			console.log("对象的普通方法调用" + this.name);
		},
		show2: () => {
			console.log("对象的普通方法调用" + this.name);
		},
		show3() {
			setTimeout(() => {
				console.log("对象方法内使用定时器和箭头函数", this.name);
			}, 1000)
		},
		show4() {
			setTimeout(function() {
				console.log("对象方法内使用定时器和普通函数", this.name);
			}, 1000)
		}
	}
	jack.show();
	jack.show2();
	console.log("通过 call 为箭头函数绑定this 无效")
	jack.show2.call(jack);

	jack.show3();
	jack.show4();
}

function test1404() {

}

function test1405() {

}

function test1406() {

}

function test1407() {

}

function test1408() {

}

function test1409() {

}

function test1410() {

}
/* ---------------- 作用域 ---------------- */
function test1501() {

}

function test1502() {

}

function test1503() {

}

function test1504() {

}
/* ---------------- 闭包 ---------------- */
function test1601() {

}

function test1602() {

}

function test1603() {

}

function test1604() {

}

function test1605() {

}
/* ---------------- 对象 ---------------- */
function test1701() {

}

function test1702() {

}

function test1703() {

}

function test1704() {

}
/* ---------------- 类 ---------------- */
function test1801() {
	// 1. 定义构造函数
	function User(name, age) {
		this.name = name;
		this.age = age;
		// 方法在构造函数内定义，每个实例都有一份拷贝
		// this.show = function() {
		// 	console.log(this.name, this.age);
		// }
	}

	// 2.在原型上定义方法，所有实例共享一份
	User.prototype.name = "人"; // 静态属性
	User.prototype.show = function() {
		console.log(this.__proto__.name, this.name, this.age);
	}

	// 3. 创建实例
	var tom = new User("Tom", 20);
	tom.show();

	// 3. 定义子类
	function Student(name, age, no) {
		// 设置父类属性, 方式1
		// User.call(this, name, age);

		// 设置父类属性, 方式2
		// 以下方式需要禁止修改原型的构造函数: Student.prototype.constructor = Student
		this.__proto__.constructor.call(this, name, age);

		this.no = no;
	}

	// 4. 继承
	Student.prototype = new User();
	// Student.prototype.constructor = Student;

	// 5. 静态属性、方法
	Student.prototype.name = "学生";

	var jack = new Student("Jack", 21, "B1001");
	jack.show();
}

function test1802() {
	// 定义类
	class User {
		// 静态属性
		static name = "人";

		// 类初始化方法
		static {
			console.log("User 类初始化");
		}

		// 静态方法，只能通过类调用，不能实例调用
		static showClassName() {
			console.log(this.name + " ，静态方法，只能通过类调用，不能实例调用");
		}

		// 实例属性
		_gender = "male";
		// 私有属性
		#height;
		#weight;

		// 构造函数
		constructor(name, age) {
			this.name = name;
			this.age = age;
		}

		// 成员方法
		show() {
			console.log(User.name, this.name, this.age, this.gender);
		}

		// 属性存取器
		get gender() {
			console.log("读取 gender: ", this._gender);
			return this._gender;
		}

		set gender(value) {
			console.log("设置 gender: ", value);
			this._gender = value;
		}
	}

	User.showClassName();

	var tom = new User("Tom", 20);
	tom.show();

	var jack = new User("Jack", 25);
	jack.gender = "男";
	jack.show();


	// 子类继承
	class Student extends User {
		constructor(name, age, no) {
			// 调用父类构造函数
			super(name, age);
			this.no = no;
		}

		// 覆盖父类同名方法
		show() {
			// 不能用 super() 调用父类方法
			// super.show();  // 错
			console.log(this.name, this.age, "学号: " + this.no);
		}
	}
	var andy = new Student("Andy", 22, "B1002");
	andy.show();
}

function test1803() {

}
/* ---------------- 模块 ---------------- */
function test1901() {

}

function test1902() {

}

function test1903() {

}

function test1904() {

}

function test1905() {

}

function test1906() {

}

function test1921() {
	var phone = m1.create("iPhone", 4000);
	m1.add(phone);
	var all = m1.getAll();
	m1.remove(0);
	m1.clear();
}

/* ---------------- 反射与代理 ---------------- */
function test2001() {

}

function test2002() {

}

function test2003() {

}
/* ---------------- 定时器 ---------------- */
function test2101() {}

function test2102() {

}

function test2103() {

}

function test2104() {

}

function test2105() {

}
/* ---------------- 异步任务 ---------------- */
function test2201() {
	console.log("开启定时任务 ...");
	setTimeout(() => {
		console.log("执行定时器任务!");
	}, 1000);
	console.log("不等待，继续向下执行");
}

function test2202() {
	// event.target.onmousedown = function() {
	document.body.onmousedown = function() {
		// if (event.buttons == 1)
		console.log("点击页面: ", event);
	}
}

function test2203() {
	var xhr = new XMLHttpRequest();
	xhr.onreadystatechange = function() {
		console.log("status: " + xhr.status + ", ready:" +
			xhr.readyState + ", " + xhr.statusText);
		if (xhr.status == 200 && xhr.readyState == 4) {
			console.log(xhr.response);
		}
	}
	xhr.open("GET", "./product.json");
	xhr.send();

	// getAjax("./product.json", (xhr, data) => {
	// 	console.log(data);
	// });
}

function test2204() {
	// 定义任务构造函数
	function ajaxTask(url) {
		return new Promise(function(resolve, reject) {
			// new 之后立即执行任务
			console.log("正在执行任务: ", url);
			getAjax(url, function(xhr, data) {
				resolve(data);
			})
		});
	};

	console.log("准备执行任务 ...");

	// 不要用变量保存 Promise，因为 new Promise() 时会立即执行任务
	// var task1 = ajaxTask("./product.json");
	// var task2 = ajaxTask("./user.json");

	// 链式执行任务
	ajaxTask("./product.json").then((data) => {
		console.log("任务1执行完毕: ", data);
		// 任务1执行完后继续任务2
		return ajaxTask("./user.json");
	}).then((data) => {
		console.log("任务2执行完毕: ", data);
	});

	console.log("不等待，继续运行 ...");
}

function test2205() {

}

function test2206() {

}

function test2207() {
	var p1 = new Promise(function(resolve, reject) {
		console.log("进入Promise 1 ... ");
		setTimeout(() => {
			console.log("Promise 1  执行完毕");
			resolve("p1 执行成功");
		}, 500);
	});
	var p2 = new Promise(function(resolve, reject) {
		console.log("进入Promise 2 ... ");
		setTimeout(() => {
			console.log("Promise 2  执行完毕");
			reject("p2 执行失败");
		}, 1000);
	});

	// Promise.all: 等待所有任务都执行成功
	var r1 = Promise.all([p1, p2]);
	r1.then((data) => {
		console.log(r1);
		console.log(data);
	}).catch(err => {
		console.log(err);
	});

	// Promise.allSettled: 等待所有任务都执行完毕，无论成功失败
	var r2 = Promise.allSettled([p1, p2]);
	r2.then((data) => {
		console.log(r2);
		console.log(data);
	});
}

function test2208() {

}
/* ---------------- Ajax请求 ---------------- */
function getAjax(url, callback) {
	var xhr = new XMLHttpRequest();
	xhr.onreadystatechange = function() {
		if (xhr.status == 200 && xhr.readyState == 4) {
			callback(xhr, xhr.response);
		}
	}
	xhr.open("GET", url);
	xhr.send();
}

function test2301() {

}

function test2302() {

}

function test2303() {

}
/* ---------------- DOM/BOM ---------------- */
